package cn.iocoder.yudao.module.famous.doctor.service.diseaseLabel;

import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants;
import cn.iocoder.yudao.module.system.enums.permission.MenuTypeEnum;
import com.google.common.annotations.VisibleForTesting;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.util.*;
import cn.iocoder.yudao.module.famous.doctor.controller.admin.diseaseLabel.vo.*;
import cn.iocoder.yudao.module.famous.doctor.dal.dataobject.diseaseLabel.DiseaseLabelDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;

import cn.iocoder.yudao.module.famous.doctor.convert.diseaseLabel.DiseaseLabelConvert;
import cn.iocoder.yudao.module.famous.doctor.dal.mysql.diseaseLabel.DiseaseLabelMapper;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.famous.doctor.dal.dataobject.diseaseLabel.DiseaseLabelDO.ID_ROOT;
import static cn.iocoder.yudao.module.famous.doctor.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.MENU_NAME_DUPLICATE;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;

/**
 * 疾病标签 Service 实现类
 *
 * @author 档案
 */
@Service
@Validated
public class DiseaseLabelServiceImpl implements DiseaseLabelService {

    @Resource
    private DiseaseLabelMapper diseaseLabelMapper;

    @Override
    @CacheEvict(value = RedisKeyConstants.DISEASE_LABEL_ID_LIST, key = "#reqVO.permission",
            condition = "#reqVO.permission != null")
    public Long createDiseaseLabel(DiseaseLabelCreateReqVO createReqVO) {
        // 校验父菜单存在
        validateParentMenu(createReqVO.getParentId(), null);
        // 校验菜单（自己）
        validateMenu(createReqVO.getParentId(), createReqVO.getName(), null);
        
        // 插入
        DiseaseLabelDO diseaseLabel = DiseaseLabelConvert.INSTANCE.convert(createReqVO);
        diseaseLabelMapper.insert(diseaseLabel);
        // 返回
        return diseaseLabel.getId();
    }

    @Override
    @CacheEvict(value = RedisKeyConstants.DISEASE_LABEL_ID_LIST,
            allEntries = true) // allEntries 清空所有缓存，因为 permission 如果变更，涉及到新老两个 permission。直接清理，简单有效
    public void updateDiseaseLabel(DiseaseLabelUpdateReqVO updateReqVO) {
        // 校验更新的菜单是否存在
        if (diseaseLabelMapper.selectById(updateReqVO.getId()) == null) {
            throw exception(MENU_NOT_EXISTS);
        }
        // 校验父菜单存在
        validateParentMenu(updateReqVO.getParentId(), updateReqVO.getId());
        // 校验菜单（自己）
        validateMenu(updateReqVO.getParentId(), updateReqVO.getName(), updateReqVO.getId());

        // 更新
        DiseaseLabelDO updateObj = DiseaseLabelConvert.INSTANCE.convert(updateReqVO);
        diseaseLabelMapper.updateById(updateObj);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = RedisKeyConstants.DISEASE_LABEL_ID_LIST,
            allEntries = true) // allEntries 清空所有缓存，因为此时不知道 id 对应的 permission 是多少。直接清理，简单有效
    public void deleteDiseaseLabel(Long id) {
        // 校验是否还有子菜单
        if (diseaseLabelMapper.selectCountByParentId(id) > 0) {
            throw exception(MENU_EXISTS_CHILDREN);
        }
        // 校验删除的菜单是否存在
        if (diseaseLabelMapper.selectById(id) == null) {
            throw exception(MENU_NOT_EXISTS);
        }
        // 校验存在
        validateDiseaseLabelExists(id);
        // 删除
        diseaseLabelMapper.deleteById(id);
    }

    private void validateDiseaseLabelExists(Long id) {
        if (diseaseLabelMapper.selectById(id) == null) {
            throw exception(DISEASE_LABEL_NOT_EXISTS);
        }
    }

    @Override
    public DiseaseLabelDO getDiseaseLabel(Long id) {
        return diseaseLabelMapper.selectById(id);
    }

    @Override
    public List<DiseaseLabelDO> getDiseaseLabelList(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return ListUtil.empty();
        }
        return diseaseLabelMapper.selectBatchIds(ids);
    }

    @Override
    public List<DiseaseLabelDO> getDiseaseLabelList() {
        return diseaseLabelMapper.selectList(new LambdaQueryWrapperX<DiseaseLabelDO>()
                .eq(DiseaseLabelDO::getStatus,1));
    }

    @Override
    public PageResult<DiseaseLabelDO> getDiseaseLabelPage(DiseaseLabelPageReqVO pageReqVO) {
        return diseaseLabelMapper.selectPage(pageReqVO);
    }

    @Override
    public List<DiseaseLabelDO> getDiseaseLabelList(DiseaseLabelExportReqVO exportReqVO) {
        return diseaseLabelMapper.selectList(exportReqVO);
    }

    @Override
    public List<DiseaseLabelDO> getDiseaseLabelLisAll(DiseaseLabelExportReqVO createReqVO) {
        LambdaQueryWrapperX<DiseaseLabelDO> diseaseLabelDOLambdaQueryWrapperX = new LambdaQueryWrapperX<DiseaseLabelDO>()
                .likeIfPresent(DiseaseLabelDO::getName, createReqVO.getName())
                .eqIfPresent(DiseaseLabelDO::getLabelType, createReqVO.getLabelType())
                .eqIfPresent(DiseaseLabelDO::getStatus, createReqVO.getStatus())
                .orderByDesc(DiseaseLabelDO::getId);
        return diseaseLabelMapper.selectList(diseaseLabelDOLambdaQueryWrapperX);
    }

    /**
     * 校验父菜单是否合法
     * <p>
     * 1. 不能设置自己为父菜单
     * 2. 父菜单不存在
     * 3. 父菜单必须是 {@link MenuTypeEnum#MENU} 菜单类型
     *
     * @param parentId 父菜单编号
     * @param childId  当前菜单编号
     */
    @VisibleForTesting
    void validateParentMenu(Long parentId, Long childId) {
        if (parentId == null || ID_ROOT.equals(parentId)) {
            return;
        }
        // 不能设置自己为父菜单
        if (parentId.equals(childId)) {
            throw exception(MENU_PARENT_ERROR);
        }
        DiseaseLabelDO diseaseLabeldo = diseaseLabelMapper.selectById(parentId);
        // 父菜单不存在
        if (diseaseLabeldo == null) {
            throw exception(MENU_PARENT_NOT_EXISTS);
        }
    }

    /**
     * 校验菜单是否合法
     * <p>
     * 1. 校验相同父菜单编号下，是否存在相同的菜单名
     *
     * @param name     菜单名字
     * @param parentId 父菜单编号
     * @param id       菜单编号
     */
    @VisibleForTesting
    void validateMenu(Long parentId, String name, Long id) {
        DiseaseLabelDO diseaseLabeldo = diseaseLabelMapper.selectByParentIdAndName(parentId, name);
        if (diseaseLabeldo == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的菜单
        if (id == null) {
            throw exception(MENU_NAME_DUPLICATE);
        }
        if (!diseaseLabeldo.getId().equals(id)) {
            throw exception(MENU_NAME_DUPLICATE);
        }
    }

}
